﻿using System;

namespace IceDog.DNF.Program.Poker.Core
{
    /// <summary>
    /// 卡牌对象
    /// </summary>
    public partial class Card : ICloneable, IComparable<Card>, IComparable
    {
        //因为IsAceHigh、Trump，UseTrump是所有卡片在一副牌中共有的属性，所以写成静态成员，而不是属性，
        //Suit、Rank则是每张牌都有各自的属性，所以是属性

        /// <summary>
        /// 使用王牌花色(即在花色不同的情况下，此花色比其他的花色大，牌面符号大小无用)
        /// </summary>
        public static bool UseTrump = false;
        /// <summary>
        /// 设置王牌花色(即在花色不同的情况下，此花色比其他的花色大，牌面符号大小无用)
        /// </summary>
        public static Suit Trump = Suit.Club;
        /// <summary>
        /// 判断A点是比K大还是比2小，如果是true，则是最大的牌，否则是最小的牌
        /// </summary>
        public static bool IsAceHigh = true;
        /// <summary>
        /// 花色
        /// </summary>
        public Suit Suit { get; }
        /// <summary>
        /// 序号
        /// </summary>
        public Rank Rank { get; }

        /// <summary>
        /// 禁用默认构造函数
        /// </summary>
        private Card() { }

        /// <summary>
        /// 自定义构造函数
        /// </summary>
        /// <param name="suit">花色</param>
        /// <param name="rank">牌面符号</param>
        public Card(Suit suit, Rank rank)
        {
            Suit = suit;
            Rank = rank;
        }

        /// <summary>
        /// 重写tostring
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return $"{Suit} {Rank}";
        }

        /// <summary>
        /// 输出中文
        /// </summary>
        /// <returns></returns>
        public string ToChineseString()
        {
            string[] suitArr = { "梅花", "方块", "红桃", "黑桃" };
            string[] rankArr = { "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K" };
            return $"{suitArr[(int)Suit - 1]} {rankArr[(int)Rank - 1]}";
        }

        /// <summary>
        /// 实现浅复制
        /// </summary>
        /// <returns></returns>
        public object Clone()
        {
            return MemberwiseClone();
        }

        /// <summary>
        /// 实现浅复制
        /// </summary>
        /// <returns></returns>
        protected Card CloneCard()
        {
            return MemberwiseClone() as Card;
        }
        /// <summary>
        /// 重载大于运算符,判断 card1&gt;card2
        /// </summary>
        /// <param name="card1">卡片1</param>
        /// <param name="card2">卡片2</param>
        /// <returns></returns>
        public static bool operator >(Card card1, Card card2)
        {
            //只有花色相同才比较大小
            if (card1.Suit == card2.Suit)
            {
                //如果A是最小
                if (!IsAceHigh)
                {
                    return card1.Rank > card2.Rank;
                }
                //如果A是最大，且卡片1是A
                if (card1.Rank == Rank.Ace)
                {
                    //则判断卡片2是不是A
                    return card2.Rank != Rank.Ace;
                }
                //如果A是最大，且卡片2是A
                if (card2.Rank == Rank.Ace)
                {
                    return false;
                }
                //否则正常比较
                return card1.Rank > card2.Rank;
            }
            //如果使用王牌花色，且card2的花色是王牌花色，则false
            return !(UseTrump && card2.Suit == Trump);
        }

        /// <summary>
        /// 重载小于运算符,判断 card1&lt;card2
        /// </summary>
        /// <param name="card1">卡片1</param>
        /// <param name="card2">卡片2</param>
        /// <returns></returns>
        public static bool operator <(Card card1, Card card2)
        {
            return !(card1 > card2);
        }

        /// <summary>
        /// 重载大于等于运算符,判断 card1&gt;=card2
        /// </summary>
        /// <param name="card1">卡片1</param>
        /// <param name="card2">卡片2</param>
        /// <returns></returns>
        public static bool operator >=(Card card1, Card card2)
        {
            return (card1 > card2) || (card1 == card2);
        }

        /// <summary>
        /// 重载小于等于运算符,判断 card1&lt;=card2
        /// </summary>
        /// <param name="card1">卡片1</param>
        /// <param name="card2">卡片2</param>
        /// <returns></returns>
        public static bool operator <=(Card card1, Card card2)
        {
            return !(card1 >= card2);
        }
        /// <summary>
        /// 重载等于运算符,判断 card1==card2
        /// </summary>
        /// <param name="card1">卡片1</param>
        /// <param name="card2">卡片2</param>
        /// <returns></returns>
        public static bool operator ==(Card card1, Card card2)
        {
            return card2 != null && (card1 != null && ((card1.Suit == card2.Suit) && (card1.Rank == card2.Rank)));
        }
        /// <summary>
        /// 重载不等于运算符,判断 card1!=card2
        /// </summary>
        /// <param name="card1">卡片1</param>
        /// <param name="card2">卡片2</param>
        /// <returns></returns>
        public static bool operator !=(Card card1, Card card2)
        {
            return !(card1 == card2);
        }

        /// <summary>重载Equals方法,确定指定的对象是否等于当前对象。</summary>
        /// <param name="obj">要与当前对象进行比较的对象。</param>
        /// <returns>
        ///   如果指定的对象等于当前对象，则为 <see langword="true" />，否则为 <see langword="false" />。
        /// </returns>
        public override bool Equals(object obj)
        {
            return Equals(this, (Card)obj);
        }

        /// <summary>重载Equals方法,确定指定的对象是否等于当前对象。</summary>
        /// <param name="card">要与当前对象进行比较的card对象。</param>
        /// <returns>
        ///   如果指定的对象等于当前对象，则为 <see langword="true" />，否则为 <see langword="false" />。
        /// </returns>
        protected bool Equals(Card card)
        {
            return this == card;
        }

        /// <summary>重载GetHashCode,作为默认哈希函数。</summary>
        /// <returns>当前对象的哈希代码。</returns>
        public override int GetHashCode()
        {
            return ((int)Suit - 1) * 13 + (int)Rank;
        }

        /// <summary>
        ///   将当前实例与同一类型的另一个对象进行比较，并返回一个整数，该整数指示当前实例在排序顺序中的位置是位于另一个对象之前、之后还是与其位置相同。
        /// </summary>
        /// <param name="card">与此实例进行比较的对象。</param>
        /// <returns>
        /// 一个值，指示要比较的对象的相对顺序。
        ///  返回值的含义如下：
        ///         值
        ///         含义
        ///         小于零
        ///         此实例在排序顺序中位于 <paramref name="card" /> 之前。
        ///         零
        ///         此实例中出现的相同位置在排序顺序中是 <paramref name="card" />。
        ///         大于零
        ///         此实例在排序顺序中位于 <paramref name="card" /> 之后。
        ///       </returns>
        public int CompareTo(Card card)
        {
            return GetHashCode() - card.GetHashCode();
        }

        /// <summary>
        ///   将当前实例与同一类型的另一个对象进行比较，并返回一个整数，该整数指示当前实例在排序顺序中的位置是位于另一个对象之前、之后还是与其位置相同。
        /// </summary>
        /// <param name="obj">与此实例进行比较的对象。</param>
        /// <returns>
        /// 一个值，指示要比较的对象的相对顺序。
        ///  返回值的含义如下：
        ///         值
        ///         含义
        ///         小于零
        ///         此实例在排序顺序中位于 <paramref name="obj" /> 之前。
        ///         零
        ///         此实例在排序顺序中的同一位置中发生<paramref name="obj" />。
        ///         大于零
        ///         此实例在排序顺序中位于 <paramref name="obj" /> 之后。
        ///       </returns>
        /// <exception cref="T:System.ArgumentException">
        ///   <paramref name="obj" />不是与此实例相同的类型。
        /// </exception>
        public int CompareTo(object obj)
        {
            return CompareTo((Card)obj);
        }
    }
}
